home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / CW GUSI 1.6.4 / src / GUSIUNIX.cp < prev    next >
Text File  |  1995-11-05  |  37KB  |  1,626 lines

  1. /*********************************************************************
  2. Project    :    GUSI                -    Grand Unified Socket Interface
  3. File        :    GUSIUnix.cp        -    Implementation of Unix domain calls
  4. Author    :    Matthias Neeracher
  5. Language    :    MPW C/C++
  6.  
  7. $Log: GUSIUnix.cp,v $
  8. Revision 1.3  1994/12/30  20:20:19  neeri
  9. Add (untested) PowerPC support.
  10.  
  11. Revision 1.2  1994/08/10  00:00:35  neeri
  12. Sanitized for universal headers.
  13.  
  14. Revision 1.1  1994/02/25  02:31:11  neeri
  15. Initial revision
  16.  
  17. Revision 0.13  1993/02/07  00:00:00  neeri
  18. New configuration scheme
  19.  
  20. Revision 0.12  1993/01/17  00:00:00  neeri
  21. Be more careful about User interrupts
  22.  
  23. Revision 0.11  1992/11/15  00:00:00  neeri
  24. Rename GUSIFSp_P.h to TFileSpec.h (there we go again)
  25.  
  26. Revision 0.10  1992/09/13  00:00:00  neeri
  27. Always complete write
  28.  
  29. Revision 0.9  1992/09/12  00:00:00  neeri
  30. Renamed Paths.h to GUSIFSp_P.h
  31.  
  32. Revision 0.8  1992/08/10  00:00:00  neeri
  33. select() for accept/connect
  34.  
  35. Revision 0.7  1992/07/26  00:00:00  neeri
  36. Error in using memccpy()
  37.  
  38. Revision 0.6  1992/07/13  00:00:00  neeri
  39. In spirit of Unix implementation, use file, not hash table
  40.  
  41. Revision 0.5  1992/05/21  00:00:00  neeri
  42. Implemented select()
  43.  
  44. Revision 0.4  1992/04/24  00:00:00  neeri
  45. Introducing UnixStreamSocket, UnixDgramSocket
  46.  
  47. Revision 0.3  1992/04/20  00:00:00  neeri
  48. C++ rewrite
  49.  
  50. Revision 0.2  1992/04/18  00:00:00  neeri
  51. On with the show, good health to you
  52.  
  53. Revision 0.1  1992/03/31  00:00:00  neeri
  54. unix domain socket calls
  55.  
  56. *********************************************************************/
  57.  
  58. #include "GUSIFile_P.h"
  59. #include <TFileSpec.h>
  60.  
  61. #include <Processes.h>
  62. #include <Resources.h>
  63. #include <LowMem.h>
  64. #include <Finder.h>
  65.  
  66. /*
  67.  * In a fit of hubris, I had assumed that the format of vtables in a C++ 
  68.  * object would remain constant forever, and furthermore hadn't paid 
  69.  * attention to issues of PowerPC compatibility. 
  70.  *
  71.  * To remedy the situation, I have to emulate the original CFront generated 
  72.  * code to some degree.
  73.  */
  74.  
  75. #if GENERATINGPOWERPC || defined(__MWERKS__)
  76. #define EMULATE_CFRONT
  77. #define EMULATE_VIRTUAL 
  78. #else
  79. #define EMULATE_VIRTUAL virtual
  80. #endif
  81.  
  82. #if GENERATING68K
  83. #pragma segment GUSIUnix
  84. #endif
  85.  
  86. class UnixSocketDomain : public SocketDomain {
  87. public:
  88.     UnixSocketDomain()    :    SocketDomain(AF_UNIX)    {        }
  89.  
  90.     Socket *     socket(int type, short protocol);
  91.     int             choose(
  92.                         int         type, 
  93.                         char *     prompt, 
  94.                         void *     constraint,        
  95.                         int         flags,
  96.                         void *     name, 
  97.                         int *     namelen);
  98. };
  99.  
  100. static UnixSocketDomain    UnixSockets;
  101.  
  102. class UnixSocket;                                    // That's what this file's all about
  103. class UnixStreamSocket;
  104. class UnixDgramSocket;
  105.  
  106. #if PRAGMA_ALIGN_SUPPORTED
  107. #pragma options align=mac68k
  108. #endif
  109. struct UnixSocketAddr : TFileSpec {
  110.     Boolean        valid;
  111.     Boolean        owned;
  112.     
  113.     UnixSocketAddr();
  114.     UnixSocketAddr(TFileSpec spec);
  115. };
  116. #if PRAGMA_ALIGN_SUPPORTED
  117. #pragma options align=reset
  118. #endif
  119.  
  120. // The interface of this class should never be changed now the first version 
  121. // of GUSI is released. All further changes should be done by making a subclass.
  122. // The Version() method must return *increasing* version numbers.
  123.  
  124. // Version 2 adds support for aborting a connection, see below
  125.  
  126. #if PRAGMA_ALIGN_SUPPORTED
  127. #pragma options align=mac68k
  128. #endif
  129. #ifdef EMULATE_CFRONT
  130. class UnixChannel {
  131. #else
  132. class UnixChannel : public SingleObject {
  133. #endif
  134.     UnixSocketAddr    address;
  135.     
  136.     void UnBind();
  137. protected:
  138.     UnixSocket *     sock;
  139. public:
  140.     UnixChannel    *    nextListener;
  141.     int                errno;
  142. #ifdef EMULATE_CFRONT
  143.     UniversalProcPtr * emulated_vtable;
  144. #endif
  145.     
  146.     UnixChannel(UnixSocket * owner);
  147.     EMULATE_VIRTUAL ~UnixChannel();
  148.     
  149.     EMULATE_VIRTUAL int            Version();
  150.     
  151.     EMULATE_VIRTUAL Boolean    Bind(UnixSocketAddr & addr);
  152.     EMULATE_VIRTUAL Boolean    Connect(UnixChannel * ch);
  153.     EMULATE_VIRTUAL Boolean    Accept(UnixChannel * ch);
  154.  
  155.     EMULATE_VIRTUAL int        Read(void * buffer, int len);
  156.     EMULATE_VIRTUAL int        Write(void * buffer, int len);
  157.     EMULATE_VIRTUAL int        Send(UnixChannel * from, void * buffer, int len);
  158.     EMULATE_VIRTUAL int         ReadAvail();
  159.     EMULATE_VIRTUAL int        WriteAvail();
  160.     EMULATE_VIRTUAL int        BufSize();
  161.     EMULATE_VIRTUAL void     DiscardRead(int len);
  162.     EMULATE_VIRTUAL void     ShutDown(int how);
  163.     EMULATE_VIRTUAL void        Disconnect();
  164.     
  165.     EMULATE_VIRTUAL int        GUSI_error(int err);
  166.  
  167.     EMULATE_VIRTUAL UnixSocketAddr & 
  168.                             Address();
  169. };
  170.  
  171. class UnixChannel2 : public UnixChannel {
  172. public:
  173.     UnixChannel2(UnixSocket * owner);
  174.  
  175. #ifndef EMULATE_CFRONT
  176.     int            Version();
  177. #endif
  178.     EMULATE_VIRTUAL void        Orphan();
  179.     EMULATE_VIRTUAL void        AbortConnect(UnixChannel * ch);
  180. };
  181. #if PRAGMA_ALIGN_SUPPORTED
  182. #pragma options align=reset
  183. #endif
  184.  
  185.  
  186. #ifdef EMULATE_CFRONT
  187. class UnixChannel;
  188.  
  189. #if GENERATING68K
  190. #pragma pointers_in_D0
  191. #endif
  192.  
  193. void Delete_UnixChannel(UnixChannel * chan)
  194. {
  195.     delete chan;
  196. }
  197.  
  198. int Version_UnixChannel(UnixChannel * chan)
  199. {
  200.     return chan->Version();
  201. }
  202.  
  203. Boolean Bind_UnixChannel(UnixChannel * chan, UnixSocketAddr & addr)
  204. {
  205.     return chan->Bind(addr);
  206. }
  207.  
  208. Boolean Connect_UnixChannel(UnixChannel * chan, UnixChannel * ch)
  209. {
  210.     return chan->Connect(ch);
  211. }
  212.  
  213. Boolean Accept_UnixChannel(UnixChannel * chan, UnixChannel * ch)
  214. {
  215.     return chan->Accept(ch);
  216. }
  217.  
  218. int Read_UnixChannel(UnixChannel * chan, void * buffer, int len)
  219. {
  220.     return chan->Read(buffer, len);
  221. }
  222.  
  223. int Write_UnixChannel(UnixChannel * chan, void * buffer, int len)
  224. {
  225.     return chan->Write(buffer, len);
  226. }
  227.  
  228. int Send_UnixChannel(UnixChannel * chan, UnixChannel * from, void * buffer, int len)
  229. {
  230.     return chan->Send(from, buffer, len);
  231. }
  232.  
  233. int ReadAvail_UnixChannel(UnixChannel * chan)
  234. {
  235.     return chan->ReadAvail();
  236. }
  237.  
  238. int WriteAvail_UnixChannel(UnixChannel * chan)
  239. {
  240.     return chan->WriteAvail();
  241. }
  242.  
  243. int BufSize_UnixChannel(UnixChannel * chan)
  244. {
  245.     return chan->BufSize();
  246. }
  247.  
  248. void DiscardRead_UnixChannel(UnixChannel * chan, int len)
  249. {
  250.     chan->DiscardRead(len);
  251. }
  252.  
  253. void ShutDown_UnixChannel(UnixChannel * chan, int how)
  254. {
  255.     chan->ShutDown(how);
  256. }
  257.  
  258. void Disconnect_UnixChannel(UnixChannel * chan)
  259. {
  260.     chan->Disconnect();
  261. }
  262.  
  263. int GUSI_error_UnixChannel(UnixChannel * chan, int err)
  264. {
  265.     return chan->GUSI_error(err);
  266. }
  267.  
  268. UnixSocketAddr & Address_UnixChannel(UnixChannel * chan)
  269. {
  270.     return chan->Address();
  271. }
  272.  
  273. void Orphan_UnixChannel(UnixChannel2 * chan)
  274. {
  275.     chan->Orphan();
  276. }
  277.  
  278. void AbortConnect_UnixChannel(UnixChannel2 * chan, UnixChannel * ch)
  279. {
  280.     chan->AbortConnect(ch);
  281. }
  282.  
  283. #if GENERATING68K
  284. #pragma pointers_in_A0
  285. #endif
  286.  
  287. #if GENERATINGCFM
  288. enum {      
  289.     piDelete = 
  290.         kCStackBased 
  291.         | STACK_ROUTINE_PARAMETER(1, kFourByteCode),
  292.     piVersion = 
  293.         kCStackBased 
  294.             | RESULT_SIZE(kFourByteCode) 
  295.             | STACK_ROUTINE_PARAMETER(1, kFourByteCode),
  296.     piBind = 
  297.         kCStackBased 
  298.             | RESULT_SIZE(kOneByteCode) 
  299.             | STACK_ROUTINE_PARAMETER(1, kFourByteCode)
  300.             | STACK_ROUTINE_PARAMETER(2, kFourByteCode),
  301.     piConnect =
  302.         kCStackBased 
  303.             | RESULT_SIZE(kOneByteCode) 
  304.             | STACK_ROUTINE_PARAMETER(1, kFourByteCode)
  305.             | STACK_ROUTINE_PARAMETER(2, kFourByteCode),
  306.     piAccept =
  307.         kCStackBased 
  308.             | RESULT_SIZE(kOneByteCode) 
  309.             | STACK_ROUTINE_PARAMETER(1, kFourByteCode)
  310.             | STACK_ROUTINE_PARAMETER(2, kFourByteCode),
  311.     piRead =
  312.         kCStackBased 
  313.             | RESULT_SIZE(kFourByteCode) 
  314.             | STACK_ROUTINE_PARAMETER(1, kFourByteCode)
  315.             | STACK_ROUTINE_PARAMETER(2, kFourByteCode)
  316.             | STACK_ROUTINE_PARAMETER(3, kFourByteCode),
  317.     piWrite = 
  318.         kCStackBased 
  319.             | RESULT_SIZE(kFourByteCode) 
  320.             | STACK_ROUTINE_PARAMETER(1, kFourByteCode)
  321.             | STACK_ROUTINE_PARAMETER(2, kFourByteCode)
  322.             | STACK_ROUTINE_PARAMETER(3, kFourByteCode),
  323.     piSend = 
  324.         kCStackBased 
  325.             | RESULT_SIZE(kFourByteCode) 
  326.             | STACK_ROUTINE_PARAMETER(1, kFourByteCode)
  327.             | STACK_ROUTINE_PARAMETER(2, kFourByteCode)
  328.             | STACK_ROUTINE_PARAMETER(3, kFourByteCode)
  329.             | STACK_ROUTINE_PARAMETER(4, kFourByteCode),
  330.     piReadAvail = 
  331.         kCStackBased 
  332.             | RESULT_SIZE(kFourByteCode) 
  333.             | STACK_ROUTINE_PARAMETER(1, kFourByteCode),
  334.     piWriteAvail = 
  335.         kCStackBased 
  336.             | RESULT_SIZE(kFourByteCode) 
  337.             | STACK_ROUTINE_PARAMETER(1, kFourByteCode),
  338.     piBufSize = 
  339.         kCStackBased 
  340.             | RESULT_SIZE(kFourByteCode) 
  341.             | STACK_ROUTINE_PARAMETER(1, kFourByteCode),
  342.     piDiscardRead = 
  343.         kCStackBased 
  344.             | STACK_ROUTINE_PARAMETER(1, kFourByteCode)
  345.             | STACK_ROUTINE_PARAMETER(2, kFourByteCode),
  346.     piShutDown = 
  347.         kCStackBased 
  348.             | STACK_ROUTINE_PARAMETER(1, kFourByteCode)
  349.             | STACK_ROUTINE_PARAMETER(2, kFourByteCode),
  350.     piDisconnect = 
  351.         kCStackBased 
  352.             | STACK_ROUTINE_PARAMETER(1, kFourByteCode),
  353.     piGUSI_error = 
  354.         kCStackBased 
  355.             | RESULT_SIZE(kFourByteCode) 
  356.             | STACK_ROUTINE_PARAMETER(1, kFourByteCode)
  357.             | STACK_ROUTINE_PARAMETER(2, kFourByteCode),
  358.     piAddress = 
  359.         kCStackBased 
  360.             | RESULT_SIZE(kFourByteCode) 
  361.             | STACK_ROUTINE_PARAMETER(1, kFourByteCode),
  362.     piOrphan =
  363.         kCStackBased 
  364.             | STACK_ROUTINE_PARAMETER(1, kFourByteCode),
  365.     piAbortConnect =
  366.         kCStackBased 
  367.             | STACK_ROUTINE_PARAMETER(1, kFourByteCode)
  368.             | STACK_ROUTINE_PARAMETER(2, kFourByteCode)
  369. };
  370.             
  371. RoutineDescriptor rdDelete = BUILD_ROUTINE_DESCRIPTOR(piDelete, Delete_UnixChannel);
  372. RoutineDescriptor rdVersion = BUILD_ROUTINE_DESCRIPTOR(piVersion, Version_UnixChannel);
  373. RoutineDescriptor rdBind = BUILD_ROUTINE_DESCRIPTOR(piBind, Bind_UnixChannel);
  374. RoutineDescriptor rdConnect = BUILD_ROUTINE_DESCRIPTOR(piConnect, Connect_UnixChannel);
  375. RoutineDescriptor rdAccept = BUILD_ROUTINE_DESCRIPTOR(piAccept, Accept_UnixChannel);
  376. RoutineDescriptor rdRead = BUILD_ROUTINE_DESCRIPTOR(piRead, Read_UnixChannel);
  377. RoutineDescriptor rdWrite = BUILD_ROUTINE_DESCRIPTOR(piWrite, Write_UnixChannel);
  378. RoutineDescriptor rdSend = BUILD_ROUTINE_DESCRIPTOR(piSend, Send_UnixChannel);
  379. RoutineDescriptor rdReadAvail = BUILD_ROUTINE_DESCRIPTOR(piReadAvail, ReadAvail_UnixChannel);
  380. RoutineDescriptor rdWriteAvail = BUILD_ROUTINE_DESCRIPTOR(piWriteAvail, WriteAvail_UnixChannel);
  381. RoutineDescriptor rdBufSize = BUILD_ROUTINE_DESCRIPTOR(piBufSize, BufSize_UnixChannel);
  382. RoutineDescriptor rdDiscardRead = BUILD_ROUTINE_DESCRIPTOR(piDiscardRead, DiscardRead_UnixChannel);
  383. RoutineDescriptor rdShutDown = BUILD_ROUTINE_DESCRIPTOR(piShutDown, ShutDown_UnixChannel);
  384. RoutineDescriptor rdDisconnect = BUILD_ROUTINE_DESCRIPTOR(piDisconnect, Disconnect_UnixChannel);
  385. RoutineDescriptor rdGUSI_error = BUILD_ROUTINE_DESCRIPTOR(piGUSI_error, GUSI_error_UnixChannel);
  386. RoutineDescriptor rdAddress = BUILD_ROUTINE_DESCRIPTOR(piAddress, Address_UnixChannel);
  387. RoutineDescriptor rdOrphan = BUILD_ROUTINE_DESCRIPTOR(piOrphan, Orphan_UnixChannel);
  388. RoutineDescriptor rdAbortConnect = BUILD_ROUTINE_DESCRIPTOR(piAbortConnect, AbortConnect_UnixChannel);
  389.  
  390. UniversalProcPtr UnixChannel_EmulatedVTable[] = {
  391.     0,
  392.     &rdDelete,
  393.     &rdVersion,
  394.     &rdBind,
  395.     &rdConnect,
  396.     &rdAccept,
  397.     &rdRead,
  398.     &rdWrite,
  399.     &rdSend,
  400.     &rdReadAvail,
  401.     &rdWriteAvail,
  402.     &rdBufSize,
  403.     &rdDiscardRead,
  404.     &rdShutDown,
  405.     &rdDisconnect,
  406.     &rdGUSI_error,
  407.     &rdAddress,
  408.     &rdOrphan,
  409.     &rdAbortConnect,
  410.     0,
  411. };
  412. #else
  413. UniversalProcPtr UnixChannel_EmulatedVTable[] = {
  414.     0,
  415.     UniversalProcPtr(Delete_UnixChannel),
  416.     UniversalProcPtr(Version_UnixChannel),
  417.     UniversalProcPtr(Bind_UnixChannel),
  418.     UniversalProcPtr(Connect_UnixChannel),
  419.     UniversalProcPtr(Accept_UnixChannel),
  420.     UniversalProcPtr(Read_UnixChannel),
  421.     UniversalProcPtr(Write_UnixChannel),
  422.     UniversalProcPtr(Send_UnixChannel),
  423.     UniversalProcPtr(ReadAvail_UnixChannel),
  424.     UniversalProcPtr(WriteAvail_UnixChannel),
  425.     UniversalProcPtr(BufSize_UnixChannel),
  426.     UniversalProcPtr(DiscardRead_UnixChannel),
  427.     UniversalProcPtr(ShutDown_UnixChannel),
  428.     UniversalProcPtr(Disconnect_UnixChannel),
  429.     UniversalProcPtr(GUSI_error_UnixChannel),
  430.     UniversalProcPtr(Address_UnixChannel),
  431.     UniversalProcPtr(Orphan_UnixChannel),
  432.     UniversalProcPtr(AbortConnect_UnixChannel),
  433.     0,
  434. };
  435. #endif
  436.  
  437. #endif
  438.  
  439. #ifdef EMULATE_CFRONT
  440. #if GENERATINGCFM
  441. #define CUP                            CallUniversalProc
  442. #define EMUL_Delete(p) CUP(p->emulated_vtable[1], piDelete, p)
  443. #define EMUL_Version(p) (int) CUP(p->emulated_vtable[2], piVersion, p)
  444. #define EMUL_Connect(p, x) (Boolean) CUP(p->emulated_vtable[4], piConnect, p, x)
  445. #define EMUL_Accept(p, x) (Boolean) CUP(p->emulated_vtable[5], piAccept, p, x)
  446. #define EMUL_Write(p, x, y) (int) CUP(p->emulated_vtable[7], piWrite, p, x, y)
  447. #define EMUL_Send(p, x, y, z) (int) CUP(p->emulated_vtable[8], piSend, p, x, y, z)
  448. #define EMUL_ReadAvail(p) (int) CUP(p->emulated_vtable[9], piReadAvail, p)
  449. #define EMUL_WriteAvail(p) (int) CUP(p->emulated_vtable[10], piWriteAvail, p)
  450. #define EMUL_BufSize(p) (int) CUP(p->emulated_vtable[11], piBufSize, p)
  451. #define EMUL_Disconnect(p) CUP(p->emulated_vtable[14], piDisconnect, p)
  452. #define EMUL_Address(p) (* (UnixSocketAddr *) CUP(p->emulated_vtable[16], piAddress, p))
  453. #define EMUL_AbortConnect(p, x) CUP(p->emulated_vtable[18], piAbortConnect, p, x)
  454. #else
  455. #pragma pointers_in_D0
  456. inline void EMUL_Delete(UnixChannel * p) 
  457. {
  458.     ((void (*)(UnixChannel *))p->emulated_vtable[1])(p);
  459. }
  460.  
  461. inline int EMUL_Version(UnixChannel * p) 
  462. {
  463.     return ((int (*)(UnixChannel *))p->emulated_vtable[2])(p);
  464. }
  465.  
  466. inline Boolean EMUL_Connect(UnixChannel * p, UnixChannel * x) 
  467. {
  468.     return ((Boolean (*)(UnixChannel *, UnixChannel *))p->emulated_vtable[4])(p, x);
  469. }
  470.  
  471. inline Boolean EMUL_Accept(UnixChannel * p, UnixChannel * x)
  472. {
  473.     return ((Boolean (*)(UnixChannel *, UnixChannel *))p->emulated_vtable[5])(p, x);
  474. }
  475.  
  476. inline int EMUL_Write(UnixChannel * p, void * x, int y) 
  477. {
  478.     return ((int (*)(UnixChannel *, void *, int))p->emulated_vtable[7])(p, x, y);
  479. }
  480.  
  481. inline int EMUL_Send(UnixChannel * p, UnixChannel * x, void * y, int z) 
  482. {
  483.     return ((int (*)(UnixChannel *, UnixChannel *, void *, int))p->emulated_vtable[8])(p, x, y, z);
  484. }
  485.  
  486. inline int EMUL_ReadAvail(UnixChannel * p)
  487. {
  488.     return ((int (*)(UnixChannel *))p->emulated_vtable[9])(p);
  489. }
  490.  
  491. inline int EMUL_WriteAvail(UnixChannel * p) 
  492. {
  493.     return ((int (*)(UnixChannel *))p->emulated_vtable[10])(p);
  494. }
  495.  
  496. inline int EMUL_BufSize(UnixChannel * p)
  497. {
  498.     return ((int (*)(UnixChannel *))p->emulated_vtable[11])(p);
  499. }
  500.  
  501. inline void EMUL_Disconnect(UnixChannel * p)
  502. {
  503.     ((void (*)(UnixChannel *))p->emulated_vtable[14])(p);
  504. }
  505.  
  506. inline UnixSocketAddr & EMUL_Address(UnixChannel * p) 
  507. {
  508.     return ((UnixSocketAddr & (*)(UnixChannel *))p->emulated_vtable[16])(p);
  509. }
  510.  
  511. inline void EMUL_AbortConnect(UnixChannel * p, UnixChannel * x) 
  512. {
  513.     ((void (*)(UnixChannel2 *, UnixChannel *))p->emulated_vtable[18])((UnixChannel2 *) p, x);
  514. }
  515.  
  516. #pragma pointers_in_A0
  517. #endif
  518. #else
  519. #define EMUL_Delete(p) delete p
  520. #define EMUL_Version(p) p->Version()
  521. #define EMUL_Connect(p, x) p->Connect(x)
  522. #define EMUL_Accept(p, x) p->Accept(x)
  523. #define EMUL_Write(p, x, y) p->Write(x, y)
  524. #define EMUL_Send(p, x, y, z) p->Send(x, y, z)
  525. #define EMUL_ReadAvail(p) p->ReadAvail()
  526. #define EMUL_WriteAvail(p) p->WriteAvail()
  527. #define EMUL_BufSize(p) p->BufSize()
  528. #define EMUL_Disconnect(p) p->Disconnect()
  529. #define EMUL_Address(p) p->Address()
  530. #define EMUL_AbortConnect(p, x) ((UnixChannel2 *)p)->AbortConnect(x)
  531. #endif
  532.  
  533. #if PRAGMA_ALIGN_SUPPORTED
  534. #pragma options align=mac68k
  535. #endif
  536. class UnixSocket : public Socket {
  537.     friend class UnixChannel;
  538.     friend class UnixChannel2;
  539.  
  540. #if GENERATING68K
  541.     Ptr                processA5;    /* Our A5 world */
  542. #endif    
  543. protected:
  544.     char                status;
  545.     char                state;
  546.     Boolean            nonblocking;
  547.     char                protocol;
  548.     Ptr                readBuf;
  549.     short                readBufSize;
  550.     short                readPos;
  551.     short             validBytes;
  552.     short                curListener;
  553.     short                maxListener;
  554.     UnixChannel *    chan;
  555.     UnixChannel    *    peer;
  556.     UnixChannel *    firstListener;
  557.     UnixChannel *    lastListener;
  558.  
  559.                     UnixSocket(short prot);
  560.     void            defaultbind();
  561. public:
  562.     void            Ready();
  563.  
  564.     enum {channelUnknown, channelAncient, channelSupportsConnAbort};
  565.     
  566.     virtual int    bind(void * name, int namelen);
  567.     virtual int     getsockname(void * name, int * namelen);
  568.     virtual int     getpeername(void * name, int * namelen);
  569.     virtual int    fcntl(unsigned int cmd, int arg);
  570.     virtual int    ioctl(unsigned int request, void *argp);
  571.     virtual int     shutdown(int how);
  572.     virtual int     select(Boolean * canRead, Boolean * canWrite, Boolean * exception);
  573.     virtual         ~UnixSocket();
  574. };
  575.  
  576.  
  577. #if GENERATINGCFM
  578. inline void UnixSocket::Ready() 
  579. {
  580.     UnixSockets.Ready();
  581. }
  582. #endif    
  583.  
  584. class UnixStreamSocket : public UnixSocket {
  585.     friend class UnixSocketDomain;
  586.     
  587.                     UnixStreamSocket();
  588. public:
  589.     int         listen(int qlen);
  590.     int         connect(void * address, int addrlen);
  591.     Socket * accept(void * address, int * addrlen);
  592.     int         recvfrom(void * buffer, int buflen, int flags, void * from, int * fromlen);
  593.     int         sendto(void * buffer, int buflen, int flags, void * to, int tolen);
  594.     
  595.                 ~UnixStreamSocket();
  596. };
  597.  
  598. class UnixDgramSocket : public UnixSocket {
  599.     friend class UnixSocketDomain;
  600.     
  601.                     UnixDgramSocket();
  602. public:
  603.     int     connect(void * address, int addrlen);
  604.     int     recvfrom(void * buffer, int buflen, int flags, void * from, int * fromlen);
  605.     int     sendto(void * buffer, int buflen, int flags, void * to, int tolen);
  606.     
  607.             ~UnixDgramSocket();
  608. };
  609. #if PRAGMA_ALIGN_SUPPORTED
  610. #pragma options align=reset
  611. #endif
  612.  
  613.  
  614. struct UnixSocketID {
  615.     UnixChannel    *            chan;
  616.     
  617.     AddrBlock                machine;
  618.     ProcessSerialNumber    process;
  619.     
  620.                 UnixSocketID()                                        {}
  621.                 UnixSocketID(UnixChannel * ch);
  622.     Boolean    Validate();
  623. };
  624.  
  625. /********************** UnixSocketAddr members ***********************/
  626.  
  627. inline UnixSocketAddr::UnixSocketAddr() 
  628.     : valid(false), owned(true)            
  629. {
  630. }
  631.  
  632. UnixSocketAddr::UnixSocketAddr(TFileSpec spec)
  633.     : TFileSpec(spec), valid(false), owned(true)            
  634. {
  635. }
  636.  
  637. /************************ UnixSocket members ************************/
  638.  
  639. static UnixSocketAddr * CanonizeName(void * name, int len);
  640. static void                 UncanonizeName(UnixSocketAddr & name, void * addr, int * addrlen);
  641. static UnixChannel *     LookupName(UnixSocketAddr name);
  642.  
  643. #if !GENERATINGCFM
  644. void UnixSocket::Ready() 
  645. {
  646.     long saveA5 = SetA5(long(processA5));
  647.     
  648.     UnixSockets.Ready();
  649.     
  650.     SetA5(saveA5);
  651. }
  652. #endif    
  653.  
  654. UnixSocket::UnixSocket(short prot)
  655. {
  656.     GUSI_error(0);
  657.     
  658.     readBufSize        =    DEFAULT_BUFFER_SIZE;
  659.     status            =    SOCK_STATUS_USED;
  660.     state                =    SOCK_STATE_UNCONNECTED;
  661.     nonblocking        =    false;
  662.     protocol            =    prot;
  663.     readPos            =    0;
  664.     validBytes        =    0;
  665.     curListener        =    0;
  666.     maxListener        =    0;
  667.     firstListener    =    nil;
  668.     lastListener    =    nil;
  669.     chan                =    nil;
  670.     peer                =    nil;
  671.     readBuf            =    NewPtr(readBufSize);
  672.     
  673.     if (!readBuf)
  674.         GUSI_error(ENOMEM);
  675.  
  676. #if !GENERATINGCFM
  677.     processA5        = LMGetCurrentA5();
  678. #endif    
  679. }
  680.  
  681. UnixSocket::~UnixSocket()
  682. {
  683.     if (readBuf)
  684.         DisposPtr(readBuf);
  685.     
  686.     if (protocol == SOCK_STREAM)
  687.         if (peer)
  688.             EMUL_Disconnect(peer);
  689.         else 
  690.             while (firstListener) {
  691.                 EMUL_Disconnect(firstListener);
  692.                 
  693.                 firstListener = firstListener->nextListener;
  694.             }
  695.         
  696.     if (chan)
  697.         delete chan;
  698. }
  699.  
  700. void UnixSocket::defaultbind()
  701. {
  702.     struct sockaddr_un    addr;
  703.     
  704.     addr.sun_family    =    AF_UNIX;
  705.     tmpnam(addr.sun_path);
  706.     
  707.     bind(&addr, strlen(addr.sun_path)+2);
  708. }
  709.  
  710. int UnixSocket::fcntl(unsigned int cmd, int arg)
  711. {
  712.     switch (cmd)    {
  713.     case F_GETFL:
  714.         if (nonblocking)
  715.             return FNDELAY;
  716.         else
  717.             return 0;
  718.     case F_SETFL:
  719.         if (arg & FNDELAY)
  720.             nonblocking = true;
  721.         else
  722.             nonblocking = false;
  723.             
  724.         return 0;
  725.     default:
  726.         return GUSI_error(EOPNOTSUPP);
  727.     }
  728. }
  729.  
  730. int UnixSocket::ioctl(unsigned int request, void *argp)
  731. {
  732.     switch (request)    {
  733.     case FIONBIO:
  734.         nonblocking    =    (Boolean) *(long *) argp;
  735.         
  736.         return 0;
  737.     case FIONREAD:
  738.         if (chan)
  739.             *(long *) argp = EMUL_ReadAvail(chan);
  740.         else
  741.             *(long *) argp    = 0;
  742.  
  743.         return 0;
  744.     default:
  745.         return GUSI_error(EOPNOTSUPP);
  746.     }
  747. }
  748.  
  749. int UnixSocket::bind(void *sa_name, int sa_namelen)
  750. {
  751.     UnixSocketAddr *    addr;
  752.     
  753.     if (chan && chan->Address().valid)
  754.             return GUSI_error(EINVAL);
  755.     
  756.     addr    =    CanonizeName(sa_name, sa_namelen);
  757.     
  758.     if (!addr)
  759.         return -1;
  760.     
  761.     if (LookupName(*addr))
  762.         return GUSI_error(EADDRINUSE);
  763.  
  764.     if (!chan && !(chan = new UnixChannel2(this)))
  765.         return GUSI_error(ENOMEM);
  766.     
  767.     if (!chan->Bind(*addr))
  768.         return GUSI_error(ENOMEM);
  769.     
  770.     return 0;
  771. }
  772.  
  773. int UnixSocket::getsockname(void *name, int *namelen)
  774. {
  775.     UncanonizeName(chan->Address(), name, namelen);
  776.     
  777.     return 0;
  778. }
  779.  
  780. int UnixSocket::getpeername(void *name, int *namelen)
  781. {
  782.     if (!peer)
  783.         return GUSI_error(ENOTCONN);
  784.         
  785.     UncanonizeName(EMUL_Address(peer), name, namelen);
  786.     
  787.     return 0;
  788. }
  789.  
  790. int UnixSocket::select(Boolean * canRead, Boolean * canWrite, Boolean *)
  791. {
  792.     int    goodies = 0;
  793.     
  794.     if (canRead)
  795.         if ((state == SOCK_STATE_LIS_CON) || !chan || chan->ReadAvail())    {
  796.             *canRead    =     true;
  797.             ++goodies;
  798.         } 
  799.     
  800.     if (canWrite)
  801.         if (!peer || EMUL_WriteAvail(peer))    {
  802.             *canWrite    =     true;
  803.             ++goodies;
  804.         } 
  805.     
  806.     return goodies;
  807. }
  808.  
  809. int UnixSocket::shutdown(int how)
  810. {
  811.     if (!chan)
  812.         return GUSI_error(ENOTCONN);
  813.  
  814.     chan->ShutDown(how);
  815.     
  816.     return 0;
  817. }
  818.  
  819. /********************* UnixStreamSocket members *********************/
  820.  
  821. UnixStreamSocket::UnixStreamSocket()
  822.     :    UnixSocket(SOCK_STREAM)
  823. {
  824. }
  825.  
  826. UnixStreamSocket::~UnixStreamSocket()
  827. {
  828. }
  829.  
  830. int UnixStreamSocket::listen(int qlen)
  831. {
  832.     if (state != SOCK_STATE_UNCONNECTED)
  833.         return GUSI_error(EISCONN);
  834.         
  835.     state            =    SOCK_STATE_LISTENING;
  836.     maxListener    =    qlen;
  837.     
  838.     return 0;
  839. }
  840.  
  841. int UnixStreamSocket::connect(void *sa_name, int sa_namelen)
  842. {
  843.     UnixSocketAddr *    addr;
  844.     UnixChannel    *    other;
  845.     
  846.     if (peer)
  847.         return GUSI_error(EISCONN);
  848.     
  849.     addr    =    CanonizeName(sa_name, sa_namelen);
  850.     
  851.     if (!addr)
  852.         return -1;
  853.     
  854.     other = LookupName(*addr);
  855.     
  856.     if (!other)
  857.         return GUSI_error(ECONNREFUSED);
  858.  
  859.     if (!chan && !(chan = new UnixChannel2(this)))
  860.         return GUSI_error(ENOMEM);
  861.     
  862.     if (!chan->Address().valid)
  863.         defaultbind();
  864.     
  865.     if (!EMUL_Connect(other, chan))
  866.         return GUSI_error(ECONNREFUSED);
  867.         
  868.     state    =    SOCK_STATE_CONNECTING;
  869.     
  870.     if (nonblocking)
  871.         return GUSI_error(EINPROGRESS);
  872.         
  873.     SAFESPIN(state == SOCK_STATE_CONNECTING, SP_MISC, 0);
  874.     
  875.     if (state == SOCK_STATE_CONNECTED)
  876.         return 0;
  877.     else if (!errno)
  878.         return GUSI_error(ECONNREFUSED);
  879.         
  880.     // User abort, a tricky situation. What we do depends on the peer channel
  881.     // version.
  882.     
  883.     if (EMUL_Version(other) >= channelSupportsConnAbort)    // The new way
  884.         EMUL_AbortConnect(other, chan);    
  885.     else                                                                    // The old way
  886.         ((UnixChannel2 *) other)->UnixChannel2::Orphan();    // This type cast is safe            
  887.     
  888.     return -1;
  889. }
  890.  
  891. Socket * UnixStreamSocket::accept(void * address, int * addrlen)
  892. {
  893.     UnixStreamSocket *    newsock;
  894.     
  895.     if (state != SOCK_STATE_LISTENING && state != SOCK_STATE_LIS_CON)
  896.         return (Socket *) GUSI_error_nil(ENOTCONN);
  897.  
  898. restart:    
  899.     if (!curListener)
  900.         if (nonblocking)
  901.             return (Socket *) GUSI_error_nil(EWOULDBLOCK);
  902.         else
  903.             SPINP(state == SOCK_STATE_LISTENING, SP_MISC, 0);
  904.             
  905.     if (!curListener)
  906.             return (Socket *) GUSI_error_nil(EINVAL);                    // I *really* hope this won't happen 
  907.  
  908.     newsock    =    new UnixStreamSocket;
  909.     
  910.     if (!newsock)
  911.         return (Socket *) GUSI_error_nil(ENOMEM);
  912.     
  913.     newsock->state            =    SOCK_STATE_CONNECTED;
  914.     newsock->peer            =    firstListener;
  915.     newsock->chan            =    new UnixChannel2(newsock);
  916.     
  917.     if (!newsock->chan)    {
  918.         delete newsock;
  919.         
  920.         return (Socket *) GUSI_error_nil(ENOMEM);
  921.     }
  922.     
  923.     newsock->chan->Address()            =    chan->Address();
  924.     newsock->chan->Address().owned    =    false;
  925.     
  926.     firstListener    =    firstListener->nextListener;
  927.     
  928.     if (!firstListener)
  929.         lastListener = nil;
  930.     
  931.     if (!--curListener)
  932.         state = SOCK_STATE_LISTENING;
  933.     
  934.     if (EMUL_Accept(newsock->peer, newsock->chan) == -1)    {
  935.         newsock->peer = nil;
  936.         
  937.         delete newsock;
  938.         
  939.         goto restart;
  940.     }
  941.  
  942.     UncanonizeName(EMUL_Address(newsock->peer), address, addrlen);
  943.     
  944.     return newsock;
  945. }
  946.  
  947. int UnixStreamSocket::recvfrom(void * buffer, int buflen, int flags, void * from, int *)
  948. {
  949.     int                avail;
  950.     
  951.     if (flags || from)
  952.         return GUSI_error(EOPNOTSUPP);
  953.     if (!chan || !peer)
  954.         return GUSI_error(ENOTCONN);    
  955.         
  956.     if ((avail = chan->ReadAvail()) == -1)
  957.         if (chan->errno == ESHUTDOWN)
  958.             return 0;
  959.         else
  960.             return GUSI_error(chan->errno);
  961.     
  962.     if (nonblocking && !avail)
  963.         return GUSI_error(EWOULDBLOCK);
  964.     
  965.     errno    =    0;
  966.     SPIN(!(avail = chan->Read(buffer, buflen)), SP_STREAM_READ, 0);
  967.     if (avail == -1 && !errno)
  968.         if (chan->errno == ESHUTDOWN)
  969.             return 0;
  970.         else
  971.             GUSI_error(chan->errno);
  972.             
  973.     return avail;
  974. }
  975.  
  976. int UnixStreamSocket::sendto(void * buffer, int buflen, int flags, void * to, int)
  977. {
  978.     int     avail;
  979.     int    done;
  980.     
  981.     if (flags || to)
  982.         return GUSI_error(EOPNOTSUPP);
  983.     if (!chan || !peer)
  984.         return GUSI_error(ENOTCONN);    
  985.         
  986.     if ((avail = EMUL_WriteAvail(peer)) == -1)
  987.         return GUSI_error(peer->errno);
  988.     
  989.     if (nonblocking && !avail)
  990.         return GUSI_error(EWOULDBLOCK);
  991.     
  992.     for (
  993.         done = errno = 0; 
  994.         !errno && buflen; 
  995.         buflen -= avail, buffer = Ptr(buffer) + avail
  996.     )    {
  997.         SPIN(!(avail = EMUL_Write(peer, buffer, buflen)), SP_STREAM_WRITE, 0);
  998.         if (avail == -1) {
  999.             if (!errno)
  1000.                 GUSI_error(peer->errno);
  1001.                 
  1002.             break;
  1003.         } 
  1004.         
  1005.         done += avail;
  1006.         
  1007.         if (nonblocking)
  1008.             break;
  1009.     }
  1010.             
  1011.     return done ? done : (buflen ? -1 : 0);
  1012. }
  1013.  
  1014. /********************* UnixDgramSocket members **********************/
  1015.  
  1016. UnixDgramSocket::UnixDgramSocket()
  1017.     :    UnixSocket(SOCK_DGRAM)
  1018. {
  1019. }
  1020.  
  1021. UnixDgramSocket::~UnixDgramSocket()
  1022. {
  1023. }
  1024.  
  1025. int UnixDgramSocket::connect(void *sa_name, int sa_namelen)
  1026. {
  1027.     UnixSocketAddr *    addr;
  1028.     
  1029.     addr    =    CanonizeName(sa_name, sa_namelen);
  1030.     
  1031.     if (!addr)
  1032.         return -1;
  1033.     
  1034.     peer = LookupName(*addr);
  1035.     
  1036.     if (!peer)
  1037.         return GUSI_error(ECONNREFUSED);
  1038.     
  1039.     state    =    SOCK_STATE_CONNECTED;
  1040.     
  1041.     return 0;
  1042. }
  1043.  
  1044. int UnixDgramSocket::recvfrom(void * buffer, int buflen, int flags, void * from, int * fromlen)
  1045. {
  1046.     UnixChannel *     partner;
  1047.     int                length;
  1048.     int                avail;
  1049.     
  1050.     if (flags)
  1051.         return GUSI_error(EOPNOTSUPP);
  1052.     if (!chan || !chan->Address().valid)
  1053.         return GUSI_error(ENOTCONN);    // fuck UNIX semantics; it's impossible for another
  1054.                                                 // socket to communicate with this one, anyway
  1055.         
  1056.     if ((avail = chan->ReadAvail()) == -1)
  1057.         return GUSI_error(chan->errno);
  1058.     
  1059.     // Datagram sockets communicate the sender's address in the first 4 bytes
  1060.     // The transfer will be atomic, so only one spin is needed
  1061.     
  1062.     if (nonblocking && !avail)
  1063.         return GUSI_error(EWOULDBLOCK);
  1064.     
  1065.     errno    =    0;
  1066.     SPIN(!(avail = chan->Read(&partner, sizeof(UnixChannel *))), SP_DGRAM_READ, 0);
  1067.     if (errno)
  1068.         return -1;
  1069.     else if (avail == -1)
  1070.         return GUSI_error(chan->errno);
  1071.     else if (avail < int(sizeof(UnixChannel *)))
  1072.         return GUSI_error(EINVAL);
  1073.  
  1074.     if ((avail = chan->Read(&length, sizeof(long))) == -1)
  1075.         return GUSI_error(chan->errno);
  1076.     
  1077.     buflen = min(buflen, length);
  1078.     
  1079.     if ((avail = chan->Read(buffer, buflen)) == -1)
  1080.         return GUSI_error(chan->errno);
  1081.         
  1082.     chan->DiscardRead(length - buflen);
  1083.     
  1084.     UncanonizeName(EMUL_Address(partner), from, fromlen);
  1085.         
  1086.     return avail;
  1087. }
  1088.  
  1089. int UnixDgramSocket::sendto(void * buffer, int buflen, int flags, void * to, int tolen)
  1090. {
  1091.     UnixSocketAddr *    addr;
  1092.     UnixChannel *         partner;
  1093.     int                    length;
  1094.     int                    avail;
  1095.     
  1096.     if (flags)
  1097.         return GUSI_error(EOPNOTSUPP);
  1098.     if (!chan)
  1099.         chan = new UnixChannel2(this);
  1100.     if (peer)    
  1101.         partner    =    peer;
  1102.     else {
  1103.         addr    =    CanonizeName(to, tolen);
  1104.         
  1105.         if (!addr)
  1106.             return -1;
  1107.         
  1108.         partner = LookupName(*addr);
  1109.         
  1110.         if (!partner)
  1111.             return GUSI_error(ECONNREFUSED);
  1112.     }
  1113.             
  1114.     length    =    sizeof(UnixChannel *) + sizeof(int) + buflen;
  1115.     
  1116.     if (length > EMUL_BufSize(partner))
  1117.         return GUSI_error(EMSGSIZE);
  1118.     if ((avail = EMUL_WriteAvail(partner)) == -1)
  1119.         return GUSI_error(partner->errno);
  1120.     if (avail < length)
  1121.         if (nonblocking)
  1122.             return GUSI_error(EWOULDBLOCK);
  1123.         else
  1124.             SPIN((avail=EMUL_WriteAvail(partner)) != -1 && avail<length, SP_DGRAM_WRITE, 0);
  1125.     
  1126.     if (avail == -1)
  1127.         return GUSI_error(partner->errno);
  1128.         
  1129.     errno    =    0;
  1130.     SPIN(!(avail = EMUL_Send(partner, chan, buffer, buflen)), SP_DGRAM_WRITE, 0);
  1131.     if (errno)
  1132.         return -1;
  1133.     else if (avail == -1)
  1134.         return GUSI_error(partner->errno);
  1135.         
  1136.     return avail;
  1137. }
  1138.  
  1139. /*********************** UnixChannel members ************************/
  1140.  
  1141. UnixChannel::UnixChannel(UnixSocket * owner)
  1142.     :    address(UnixSocketAddr()), sock(owner), nextListener(nil)
  1143. {
  1144. #ifdef EMULATE_CFRONT
  1145.     emulated_vtable = UnixChannel_EmulatedVTable;
  1146. #endif
  1147. }
  1148.  
  1149. UnixChannel::~UnixChannel()
  1150. {
  1151.     if (address.valid)
  1152.         UnBind();
  1153. }
  1154.  
  1155. void UnixChannel::UnBind()
  1156. {
  1157.     if (address.owned)
  1158.         HDelete(address.vRefNum, address.parID, address.name);        
  1159. }
  1160.  
  1161. int UnixChannel::Version()
  1162. {
  1163. #ifdef EMULATE_CFRONT
  1164.     return 3;
  1165. #else
  1166.     return 1;
  1167. #endif
  1168. }
  1169.  
  1170. Boolean UnixChannel::Bind(UnixSocketAddr & addr)
  1171. {
  1172.     short                resFile;
  1173.     short                oldResFile    =    CurResFile();
  1174.     Handle            ID;
  1175.     UnixSocketID    me(this);
  1176.     FInfo                info;
  1177.     
  1178.     address    =    addr;
  1179.     
  1180.     if (PtrToHand(&me, &ID, sizeof(UnixSocketID)))
  1181.         return false;
  1182.         
  1183.     HDelete(address.vRefNum, address.parID, address.name);
  1184.     HCreate(address.vRefNum, address.parID, address.name, 'GU∑I', '∑OCK');
  1185.     HCreateResFile(address.vRefNum, address.parID, address.name);
  1186.     resFile = HOpenResFile(address.vRefNum, address.parID, address.name, fsRdWrPerm);
  1187.     
  1188.     if (resFile == -1)    {
  1189.         DisposeHandle(ID);
  1190.         return false;
  1191.     }
  1192.     
  1193.     AddResource(ID, 'GU∑I', GUSIRsrcID, (StringPtr) "\p");
  1194.     
  1195.     if (ResError()) {
  1196.         CloseResFile(resFile);
  1197.         HDelete(address.vRefNum, address.parID, address.name);
  1198.         DisposeHandle(ID);
  1199.         UseResFile(oldResFile);
  1200.         return false;
  1201.     }
  1202.  
  1203.     CopyIconFamily(LMGetCurApRefNum(), GUSIRsrcID, resFile, kCustomIconResource);
  1204.     
  1205.     CloseResFile(resFile);
  1206.     UseResFile(oldResFile);
  1207.  
  1208.     HGetFInfo(address.vRefNum, address.parID, address.name, &info);
  1209.     info.fdFlags    |=    (1 << 10);
  1210.     info.fdFlags    &= ~(1 << 8);
  1211.     HSetFInfo(address.vRefNum, address.parID, address.name, &info);
  1212.         
  1213.     return true;
  1214. }
  1215.  
  1216. Boolean UnixChannel::Connect(UnixChannel * ch)
  1217. {
  1218.     if (sock->curListener >= sock->maxListener)
  1219.         return false;
  1220.         
  1221.     switch (sock->state)    {
  1222.     case SOCK_STATE_LISTENING:
  1223.         sock->state    =    SOCK_STATE_LIS_CON;
  1224.         // Fall through
  1225.     case SOCK_STATE_LIS_CON:
  1226.         if (!sock->lastListener)
  1227.             sock->firstListener    =    ch;
  1228.         else
  1229.             sock->lastListener->nextListener = ch;
  1230.             
  1231.         sock->lastListener = ch;
  1232.         ++sock->curListener;
  1233.         
  1234.         sock->Ready();
  1235.         
  1236.         return true;
  1237.     default:
  1238.         return false;
  1239.     }
  1240. }
  1241.  
  1242. Boolean UnixChannel::Accept(UnixChannel * ch)
  1243. {
  1244.     if (!sock)
  1245.         return true;
  1246.         
  1247.     sock->peer    =    ch;
  1248.     sock->state    =    SOCK_STATE_CONNECTED;
  1249.         
  1250.     sock->Ready();
  1251.     
  1252.     return true;
  1253. }
  1254.  
  1255. int UnixChannel::Read(void * buffer, int len)
  1256. {
  1257.     if (sock->status & SOCK_STATUS_NOREAD)
  1258.         return GUSI_error(ESHUTDOWN);
  1259.         
  1260.     Ptr    startBuf    = (Ptr) buffer;
  1261.     int    section;
  1262.         
  1263.     if (sock->validBytes > 0)    {
  1264.         section    =    sock->readBufSize-sock->readPos;
  1265.         
  1266.         if (section > sock->validBytes)
  1267.             section = sock->validBytes;
  1268.         if (section > len)
  1269.             section = len;
  1270.         
  1271.         BlockMove(sock->readBuf+sock->readPos, buffer, section);
  1272.         
  1273.         buffer                = (char *) buffer + section;
  1274.         sock->readPos        +=    section;
  1275.         sock->validBytes    -=    section;
  1276.         len                     -= section;
  1277.         
  1278.         if (sock->readPos == sock->readBufSize)
  1279.             sock->readPos    =    0;
  1280.     } else if (sock->state != SOCK_STATE_CONNECTED)
  1281.         return GUSI_error(ESHUTDOWN);
  1282.         
  1283.     if (len > 0 && sock->validBytes > 0)    {
  1284.         section     =    (len > sock->validBytes) ? sock->validBytes : len;
  1285.         
  1286.         BlockMove(sock->readBuf, buffer, section);
  1287.         
  1288.         buffer                = (char *) buffer + section;
  1289.         sock->readPos        +=    section;
  1290.         sock->validBytes    -=    section;
  1291.     }
  1292.         
  1293.     return (char *) buffer-startBuf;        
  1294. }
  1295.  
  1296. int UnixChannel::Write(void * buffer, int len)
  1297. {    
  1298.     if (!sock || (sock->status & SOCK_STATUS_NOWRITE))
  1299.         return GUSI_error(ESHUTDOWN);
  1300.  
  1301.     Ptr    startBuf    =    (Ptr) buffer;
  1302.     int    avail        =    sock->readBufSize - sock->validBytes;
  1303.     int    section    =    avail - sock->readPos;
  1304.         
  1305.     if (section > 0)    {
  1306.         if (section > len)
  1307.             section = len;
  1308.             
  1309.         BlockMove(buffer, sock->readBuf+sock->readPos+sock->validBytes, section);
  1310.         
  1311.         buffer                 = (char *) buffer + section;
  1312.         sock->validBytes    +=    section;
  1313.         len                     -= section;
  1314.         avail                    -=    section;
  1315.     }
  1316.     
  1317.     if (len > 0 && avail > 0)    {
  1318.         section     =    (len > avail) ? avail : len;
  1319.         
  1320.         BlockMove(buffer, sock->readBuf+sock->readPos-avail, section);
  1321.         
  1322.         buffer                 = (char *) buffer + section;
  1323.         sock->validBytes    +=    section;
  1324.     }
  1325.  
  1326.     len = (char *) buffer-startBuf;
  1327.     
  1328.     if (len)
  1329.         sock->Ready();
  1330.             
  1331.     return (char *) buffer-startBuf;        
  1332. }
  1333.  
  1334. int UnixChannel::Send(UnixChannel * from, void * buffer, int len)
  1335. {
  1336.     int length    =    sizeof(UnixChannel *) + sizeof(int) + len;
  1337.  
  1338.     if (sock->peer && sock->peer != from)
  1339.         return GUSI_error(ECONNREFUSED);
  1340.     
  1341.     if (WriteAvail() < length)
  1342.         return 0;
  1343.     
  1344.     Write(&from, sizeof(UnixChannel *));
  1345.     Write(&len, sizeof(int));
  1346.     
  1347.     return Write(buffer, len);
  1348. }
  1349.  
  1350. int UnixChannel::ReadAvail()
  1351. {
  1352.     if (sock->status & SOCK_STATUS_NOREAD)
  1353.         return GUSI_error(ESHUTDOWN);
  1354.         
  1355.     return sock->validBytes;
  1356. }
  1357.  
  1358. int UnixChannel::WriteAvail()
  1359. {
  1360.     if (!sock || (sock->status & SOCK_STATUS_NOWRITE))
  1361.         return GUSI_error(ESHUTDOWN);
  1362.         
  1363.     return sock->readBufSize - sock->validBytes;
  1364. }
  1365.  
  1366. int UnixChannel::BufSize()
  1367. {
  1368.     return sock->readBufSize;
  1369. }
  1370.  
  1371. void UnixChannel::ShutDown(int how)
  1372. {
  1373.     switch(how) {
  1374.     case 0 : 
  1375.         sock->status |= SOCK_STATUS_NOREAD;
  1376.         break;
  1377.     case 1 : 
  1378.         sock->status |= SOCK_STATUS_NOWRITE;
  1379.         break;
  1380.     case 2 :
  1381.         sock->status |= SOCK_STATUS_NOREAD | SOCK_STATUS_NOWRITE;
  1382.     }
  1383. }
  1384.  
  1385. void UnixChannel::DiscardRead(int len)
  1386. {
  1387.     if (sock->validBytes <= len)    {
  1388.         sock->validBytes    =    0;
  1389.         sock->readPos        =    0;
  1390.     } else {
  1391.         sock->validBytes    -=    len;
  1392.         sock->readPos        = (sock->readPos+len) % sock->readBufSize;
  1393.     }
  1394. }
  1395.  
  1396. void UnixChannel::Disconnect()
  1397. {
  1398.     if (sock) {
  1399.         sock->peer    =    nil;
  1400.         sock->state    =    SOCK_STATE_UNCONNECTED;
  1401.         sock->Ready();
  1402.     }
  1403. }
  1404.  
  1405. int UnixChannel::GUSI_error(int err)
  1406. {
  1407.     errno    =    err;
  1408.  
  1409.     return -1;
  1410. }
  1411.  
  1412. UnixSocketAddr & UnixChannel::Address()
  1413. {
  1414.     return address;
  1415. }
  1416.  
  1417. /*********************** UnixChannel2 members ************************/
  1418.  
  1419. UnixChannel2::UnixChannel2(UnixSocket * owner)
  1420.     :    UnixChannel(owner)
  1421. {
  1422. }
  1423.  
  1424. #ifndef EMULATE_CFRONT
  1425. int UnixChannel2::Version()
  1426. {
  1427.     return 2;
  1428. }
  1429. #endif
  1430.  
  1431. void UnixChannel2::Orphan()
  1432. {
  1433.     // Sever ties to owner
  1434.     
  1435.     sock->chan    =    nil;
  1436.     sock             =     nil;
  1437. }
  1438.  
  1439. void UnixChannel2::AbortConnect(UnixChannel * ch)
  1440. {
  1441.     UnixChannel    * prev = nil;
  1442.     
  1443.     for (UnixChannel * chan = sock->firstListener; chan; chan = chan->nextListener) {
  1444.         if (chan == ch)    {    // Got it !
  1445.             if (prev)
  1446.                 prev->nextListener    =    chan->nextListener;
  1447.             else
  1448.                 sock->firstListener    =    chan->nextListener;
  1449.             
  1450.             if (!chan->nextListener)
  1451.                 sock->lastListener    =    prev;
  1452.             
  1453.             if (!--sock->curListener)
  1454.                 sock->state = SOCK_STATE_LISTENING;
  1455.             
  1456.             sock->Ready();
  1457.             
  1458.             break;
  1459.         }
  1460.         prev = chan;
  1461.     }
  1462. }
  1463.  
  1464. /********************* UnixSocketID members **********************/
  1465.  
  1466. UnixSocketID::UnixSocketID(UnixChannel * ch)
  1467.     : chan(ch)
  1468. {
  1469.     short    net;
  1470.     short node;
  1471.     
  1472.     AppleTalkIdentity(net, node);
  1473.     
  1474.     machine.aNet    =    net;
  1475.     machine.aNode    =    node;
  1476.     machine.aSocket=    0;
  1477.     
  1478.     if (!hasProcessMgr || GetCurrentProcess(&process))    {
  1479.         process.highLongOfPSN = kNoProcess;
  1480.         process.lowLongOfPSN = kNoProcess;
  1481.     }    
  1482. }
  1483.  
  1484. Boolean UnixSocketID::Validate()
  1485. {
  1486.     UnixSocketID    me(nil);
  1487.     ProcessInfoRec    info;
  1488.     
  1489.     if (memcmp(&machine, &me.machine, sizeof(AddrBlock)))
  1490.         return false;
  1491.         
  1492.     if (!hasProcessMgr)
  1493.         return (!process.highLongOfPSN && !process.lowLongOfPSN);
  1494.     
  1495.     info.processInfoLength    =    sizeof(ProcessInfoRec);
  1496.     info.processName            =    nil;
  1497.     info.processAppSpec        =    nil;
  1498.     
  1499.     return !GetProcessInformation(&process, &info);
  1500. }
  1501.  
  1502. /********************* UnixSocketDomain member **********************/
  1503.  
  1504. extern "C" void GUSIwithUnixSockets()
  1505. {
  1506.     UnixSockets.DontStrip();
  1507. }
  1508.  
  1509. Socket * UnixSocketDomain::socket(int type, short)
  1510. {
  1511.     UnixSocket * sock    =    nil;
  1512.     
  1513.     switch (type)    {
  1514.     case SOCK_STREAM:
  1515.         sock = new UnixStreamSocket();
  1516.         break;
  1517.     case SOCK_DGRAM:
  1518.         sock = new UnixDgramSocket();
  1519.         break;
  1520.     default:
  1521.         GUSI_error(ESOCKTNOSUPPORT);
  1522.     }    
  1523.     
  1524.     if (sock && errno)    {
  1525.         delete sock;
  1526.         
  1527.         return nil;
  1528.     } else
  1529.         return sock;
  1530. }
  1531.  
  1532. int UnixSocketDomain::choose(int, char * prompt, void *, int flags, void * name, int * namelen)
  1533. {
  1534.     struct sockaddr_un *    addr = (sockaddr_un *) name;
  1535.     sa_constr_file            constr;
  1536.     
  1537.     addr->sun_family    = AF_UNIX;
  1538.  
  1539.     constr.numTypes    =    1;
  1540.     constr.types[0]    =    '∑OCK';
  1541.     
  1542.     *namelen -= 2;
  1543.     if (FileSockets->choose(0, prompt, &constr, flags, addr->sun_path, namelen))
  1544.         return -1;
  1545.     
  1546.     *namelen += 2;
  1547.     
  1548.     return 0;
  1549. }
  1550.  
  1551.  
  1552. /************************* Name conversions *************************/
  1553.  
  1554. static char                    canonPath[120];
  1555. static UnixSocketAddr    canonAddr;
  1556.  
  1557. static UnixSocketAddr * CanonizeName(void * name, int len)
  1558. {
  1559.     struct sockaddr_un *    addr = (sockaddr_un *) name;
  1560.     
  1561.     if (!name || !len || addr->sun_family != AF_UNIX)    {
  1562.         GUSI_error(EAFNOSUPPORT);
  1563.         
  1564.         return nil;
  1565.     }
  1566.     
  1567.     len -= 2;
  1568.     memcpy(canonPath, addr->sun_path, len);
  1569.     
  1570.     canonPath[len] =     0;
  1571.     canonAddr        =    TFileSpec(canonPath);
  1572.     
  1573.     if (canonAddr.Error())
  1574.         return nil;
  1575.     else
  1576.         canonAddr.valid    =    true;
  1577.         
  1578.     return &canonAddr;
  1579. }
  1580.  
  1581. static void UncanonizeName(UnixSocketAddr & name, void * addr, int * addrlen)
  1582. {
  1583.     struct sockaddr_un *    uaddr = (sockaddr_un *) addr;
  1584.     char    *                     path    =    name.FullPath();
  1585.     char     *                     end;
  1586.     int                        i;
  1587.     
  1588.     if (!addr || *addrlen < int(sizeof(short)))    {
  1589.         if (addrlen)
  1590.             *addrlen = 0;
  1591.         
  1592.         return;
  1593.     }
  1594.     
  1595.     *addrlen             -= 2;
  1596.     uaddr->sun_family =     AF_UNIX;
  1597.     
  1598.     for (i = 0; i < *addrlen; ++i)
  1599.         if (!(uaddr->sun_path[i] = path[i]))
  1600.             break;
  1601.     
  1602.     *addrlen = i+2;
  1603. }
  1604.  
  1605. static UnixChannel * LookupName(UnixSocketAddr name)
  1606. {
  1607.     short                file;
  1608.     Handle            hdl;
  1609.     UnixChannel *    cur    =    nil;
  1610.     UnixSocketID    id;
  1611.  
  1612.     file    =    HOpenResFile(name.vRefNum, name.parID, name.name, fsRdPerm);
  1613.  
  1614.     if (file != -1)    {
  1615.         if (hdl = Get1Resource('GU∑I', GUSIRsrcID))    {
  1616.             id = **(UnixSocketID **) hdl;
  1617.             
  1618.             if (id.Validate())
  1619.                 cur = id.chan;
  1620.         }
  1621.         CloseResFile(file);
  1622.     }
  1623.     
  1624.     return cur;
  1625. }
  1626.